/**
 * @file bl0906.c
 * @brief bl0906(六相交流电能计量芯片)驱动
 * @author wangh (wanghuan3037@fiberhome.com)
 * @version 1.0
 * @date 2020-10-21
 * @copyright Copyright (c) 2020  烽火通信
 ***************************************************************
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version  <th>Author  <th>Description
 * <tr><td>2020-10-21 <td>1.0      <td>wangh   <td>内容
 * </table>
 */ 
#include "bl0906.h"

#if DRV_BL0906_EN
#include "project_board.h"

#undef LOG_LEVEL_
#define LOG_LEVEL_ 	LOG_LVL_ASSERT
#include "bsp_log.h"


#define BL_READ_TIMEOUT         100
#define BL_READ_TRYTIMES        3
#define BL_RESUME_TRYTIMES      10

static void Bl0906_Config(Bl0906_t *obj);

/**
 * @brief 计算校验和 \n
 * （Addr+Data_L+Data_M+Data_H）&0xFF 取反
 * @param  buff        数据指针
 * @param  size        数据长度
 * @return uint8_t 校验和
 */
static uint8_t Bl0906_CaclCheckSum( uint8_t *buff, uint8_t size )
{
    uint16_t checksum = 0;
    for( uint8_t i=0; i<size; i++ )
        checksum = checksum + buff[i];
    return ~(uint8_t)(checksum&0xFF);
}


/**
 * @brief Bl0906读寄存器(无锁版，中间函数)
 * @param[in]  obj      Bl0906对象
 * @param[in]  reg      寄存器地址
 * @param[in]  buffer   读取数据指针
 * @param[in]  timeout  读取超时时间（ms）
 * @param[in]  trytimes 出错重试次数
 * @return int8_t 
 * - @b Sucess : BSP_SUCCESS \n
 * - @b Fail : BSP_ERROR - 超时或校验出错
 */
static int8_t Bl0906_ReadReg_Nolock( Bl0906_t *obj, uint8_t reg, uint8_t *buffer, uint32_t timeout, uint8_t trytimes )
{
    uint8_t buff[6];

    memset(buff, 0, 6);
    buff[0] = 0x35;
    buff[1] = reg;

    do{
        vTaskDelay(1);
        UartSend( obj->UartId, buff, 2 );
        if( UartRecv( obj->UartId, &buff[2], 4, portTICK_RATE_MS*timeout ) == 4 )
        {
            if( buff[5] == Bl0906_CaclCheckSum( &buff[1], 4 ) ) /* 比对校验和 */
            {
                memcpy(buffer, &buff[2], 3);
                obj->resume_times = 0;
                return BSP_SUCCESS;
            }
            else
                log_d( "Bl0906_CaclCheckSum err\r\n" );
        }
        else
        {
            log_d( "Bl0906_recv timeout\r\n" );
        }
    } while (trytimes--);

    log_e( "Bl0906_ReadReg timeout\r\n" );
    obj->resume_times++;
    if (obj->resume_times > BL_RESUME_TRYTIMES)
    {
        obj->resume_times = 0;
        UartReset( obj->UartId );   /* 复位串口回复 */
    }

    return BSP_ERROR;
}

/**
 * @brief Bl0906读寄存器
 * @param[in]  obj      Bl0906对象
 * @param[in]  reg      寄存器地址
 * @param[in]  buffer   读取数据指针
 * @param[in]  timeout  读取超时时间（ms）
 * @param[in]  trytimes 出错重试次数
 * @return int8_t 
 * - @b Sucess : BSP_SUCCESS \n
 * - @b Fail : BSP_ERROR - 超时或校验出错
 */
static int8_t Bl0906_ReadReg( Bl0906_t *obj, uint8_t reg, uint8_t *buffer, uint32_t timeout, uint8_t trytimes )
{
    xSemaphoreTake(obj->WR_lock, portMAX_DELAY);
    int8_t ret = Bl0906_ReadReg_Nolock( obj, reg, buffer, timeout, trytimes );
    xSemaphoreGive(obj->WR_lock);
    return ret;
}

/**
 * @brief Bl0906写寄存器（不校验、不加锁，中间函数）
 * @param[in]  obj      Bl0906对象
 * @param[in]  reg      寄存器地址
 * @param[in]  data     数据（24位）
 */
static void Bl0906_WriteReg_Nocheck( Bl0906_t *obj, uint8_t reg, uint32_t data )
{
    uint8_t buff[6];

    buff[0] = 0xCA;
    buff[1] = reg;
    buff[2] = (uint8_t)(data&0xFF);
    buff[3] = (uint8_t)((data>>8)&0xFF);
    buff[4] = (uint8_t)((data>>16)&0xFF);
    buff[5] = Bl0906_CaclCheckSum( &buff[1], 4 );   /* 校验和 */

    UartSend( obj->UartId, buff, 6 );
}

/**
 * @brief Bl0939写寄存器（仅支持用户操作寄存器）
 * @param[in]  obj      Bl0939对象
 * @param[in]  reg      寄存器地址
 * @param[in]  data     数据（24位）
 * @param[in]  isReadCheck 是否读取验证（false：不验证，true：验证）
 * @return int8_t 
 * - @b Sucess : BSP_SUCCESS \n
 * - @b Fail : BSP_ERROR - 超时或校验出错
 */
static int8_t Bl0906_WriteReg( Bl0906_t *obj, uint8_t reg, uint32_t data, bool isReadCheck )
{
    int8_t ret = BSP_ERROR;
    uint8_t buff[6];
    uint8_t trytimes = BL_READ_TRYTIMES;

    xSemaphoreTake(obj->WR_lock, portMAX_DELAY);
    if (!isReadCheck)
    {
        Bl0906_WriteReg_Nocheck( obj, reg, data );
        ret = BSP_SUCCESS;
        goto end;
    }

    /* 读取验证 */
    do{
        Bl0906_WriteReg_Nocheck( obj, reg, data );

        memset(buff, 0, 6);
        ret = Bl0906_ReadReg_Nolock( obj, reg, buff, BL_READ_TIMEOUT, 1 );
        if (ret == BSP_SUCCESS)
        {
            if( data == (uint32_t)(((buff[2]<<16) + (buff[1]<<8) + buff[0])&0x00FFFFFF) )
            {
                ret = BSP_SUCCESS;
                obj->resume_times = 0;
                goto end;
            }
            else
            {
                log_d( "Bl0906_WriteReg check error %08X  %08X\r\n", data, (uint32_t)(((buff[2]<<16) + (buff[1]<<8) + buff[0])&0x00FFFFFF) );
                ret = BSP_ERROR_CHECK;
            }
        }
    } while (trytimes--);

    obj->resume_times++;
    if (obj->resume_times > BL_RESUME_TRYTIMES)
    {
        obj->resume_times = 0;
        UartReset( obj->UartId );   /* 复位串口回复 */
    }

end:
    xSemaphoreGive(obj->WR_lock);
    return ret;
}

/**
 * @brief 读无符号寄存器
 * @param[in]  obj      Bl0906对象
 * @param[in]  reg      寄存器地址
 * @param[out] value    寄存器值
 * @return int8_t 
 * - @b Sucess : BSP_SUCCESS \n
 * - @b Fail : @ref Bl0906_ReadReg
 */
static int8_t Bl0906_ReadRegUint( Bl0906_t *obj, uint8_t reg, uint32_t *value )
{
    uint8_t buff[3];
    memset(buff, 0, 3);

    int8_t ret = Bl0906_ReadReg( obj, reg, buff, BL_READ_TIMEOUT, BL_READ_TRYTIMES );
    if(ret != BSP_SUCCESS)
    {
        log_e( "Bl0906_ReadReg error(%d)\r\n", ret );
        return ret;
    }
    log_v("Bl0906_ReadReg %02X %02X %02X\r\n", buff[0], buff[1], buff[2]);

    *value = (uint32_t)(((buff[2]<<16) + (buff[1]<<8) + buff[0])&0x00FFFFFF);

    return BSP_SUCCESS;
}

/**
 * @brief 读有符号寄存器
 * @param[in]  obj      Bl0906对象
 * @param[in]  reg      寄存器地址
 * @param[out] value    寄存器值
 * @return int8_t 
 * - @b Sucess : BSP_SUCCESS \n
 * - @b Fail : @ref Bl0906_ReadReg
 */
static int8_t Bl0906_ReadRegInt( Bl0906_t *obj, uint8_t reg, int32_t *value )
{
    uint32_t utemp;

    int8_t ret = Bl0906_ReadRegUint( obj, reg, &utemp );
    if (ret != BSP_SUCCESS)
        return ret;

    int32_t itemp = (int32_t)utemp;
    if( ( itemp&0x800000 ) == 0x800000 )
        itemp |= 0xff000000; /* 高位补1 */

    *value = itemp;

    return BSP_SUCCESS;
}

/**
 * @brief 电量统计超时处理函数(0.001千瓦小时)
 */
static void blTimer_timeout_ind(TimerHandle_t xTimer)
{
    uint32_t utemp1 = 0;
    uint32_t utemp2 = 0;
    uint32_t utemp3 = 0;
    uint32_t utemp4 = 0;
    uint32_t utemp5 = 0;
    uint32_t utemp6 = 0;
    uint32_t utempSum = 0;

    Bl0906_t *obj = (Bl0906_t * )pvTimerGetTimerID(xTimer);

    uint32_t utemp = 0;
    Bl0906_ReadRegUint( obj, Addr_MODE1, &utemp );
    log_v("Addr_MODE1 = %08X\r\n", utemp);
    if (utemp != 0x400000)
    {
        Bl0906_Config(obj);
        log_e( "Bl0906 reconfig...\r\n" );
    }

#if BL0906_CF1_EN
    if (BSP_SUCCESS != Bl0906_ReadRegUint( obj, Addr_CF1_CNT, &utemp1 ))
        return;
    #if BL0906_CF_CLR_SEL
    if (utemp1/obj->Energy_K > 10)
        utemp1 = 0;
    #endif
#endif

#if BL0906_CF2_EN
    if (BSP_SUCCESS != Bl0906_ReadRegUint( obj, Addr_CF2_CNT, &utemp2 ))
        return;
    #if BL0906_CF_CLR_SEL
    if (utemp2/obj->Energy_K > 10)
        utemp2 = 0;
    #endif
#endif

#if BL0906_CF3_EN
    if (BSP_SUCCESS != Bl0906_ReadRegUint( obj, Addr_CF3_CNT, &utemp3 ))
        return;
    #if BL0906_CF_CLR_SEL
    if (utemp3/obj->Energy_K > 10)
        utemp3 = 0;
    #endif
#endif

#if BL0906_CF4_EN
    if (BSP_SUCCESS != Bl0906_ReadRegUint( obj, Addr_CF4_CNT, &utemp4 ))
        return;
    #if BL0906_CF_CLR_SEL
    if (utemp4/obj->Energy_K > 10)
        utemp4 = 0;
    #endif
#endif

#if BL0906_CF5_EN
    if (BSP_SUCCESS != Bl0906_ReadRegUint( obj, Addr_CF5_CNT, &utemp5 ))
        return;
    #if BL0906_CF_CLR_SEL
    if (utemp5/obj->Energy_K > 10)
        utemp5 = 0;
    #endif
#endif

#if BL0906_CF6_EN
    if (BSP_SUCCESS != Bl0906_ReadRegUint( obj, Addr_CF6_CNT, &utemp6 ))
        return;
    #if BL0906_CF_CLR_SEL
    if (utemp6/obj->Energy_K > 10)
        utemp6 = 0;
    #endif
#endif

#if BL0906_CF_EN
    if (BSP_SUCCESS != Bl0906_ReadRegUint( obj, Addr_CF_CNT, &utempSum ))
        return;
    #if BL0906_CF_CLR_SEL
    if (utempSum/obj->Energy_K > 50)
        utempSum = 0;
    #endif
#endif

    log_v("Addr_CF3_CNT = %d\r\n", utemp3);

#if BL0906_CF_CLR_SEL   /* CF自动清零 */
#if BL0906_ENERGY_USE_FLOAT /* 能量使用浮点运算 */
    xSemaphoreTake(obj->Energy_lock, portMAX_DELAY);
    #if BL0906_CF1_EN
    obj->Energy.Energy_1 = obj->Energy.Energy_1 + (float)utemp1/obj->Energy_K;
    #endif
    #if BL0906_CF2_EN
    obj->Energy.Energy_2 = obj->Energy.Energy_2 + (float)utemp2/obj->Energy_K;
    #endif
    #if BL0906_CF3_EN
    obj->Energy.Energy_3 = obj->Energy.Energy_3 + (float)utemp3/obj->Energy_K;
    #endif
    #if BL0906_CF4_EN
    obj->Energy.Energy_4 = obj->Energy.Energy_4 + (float)utemp4/obj->Energy_K;
    #endif
    #if BL0906_CF5_EN
    obj->Energy.Energy_5 = obj->Energy.Energy_5 + (float)utemp5/obj->Energy_K;
    #endif
    #if BL0906_CF6_EN
    obj->Energy.Energy_6 = obj->Energy.Energy_6 + (float)utemp6/obj->Energy_K;
    #endif
    #if BL0906_CF_EN
    obj->Energy.Energy_Sum = obj->Energy.Energy_Sum + (float)utempSum/obj->Energy_K;
    #endif
    xSemaphoreGive(obj->Energy_lock);

#else    /* 能量使用整形运算 */
    #if BL0906_CF1_EN
    utemp1 = utemp1*1000 + obj->EnergyMid.EnergyMid_1;
    obj->EnergyMid.EnergyMid_1 = utemp1 % obj->Energy_K;
    #endif
    #if BL0906_CF2_EN
    utemp2 = utemp2*1000 + obj->EnergyMid.EnergyMid_2;
    obj->EnergyMid.EnergyMid_2 = utemp2 % obj->Energy_K;
    #endif
    #if BL0906_CF3_EN
    utemp3 = utemp3*1000 + obj->EnergyMid.EnergyMid_3;
    obj->EnergyMid.EnergyMid_3 = utemp3 % obj->Energy_K;
    #endif
    #if BL0906_CF4_EN
    utemp4 = utemp4*1000 + obj->EnergyMid.EnergyMid_4;
    obj->EnergyMid.EnergyMid_4 = utemp4 % obj->Energy_K;
    #endif
    #if BL0906_CF5_EN
    utemp5 = utemp5*1000 + obj->EnergyMid.EnergyMid_5;
    obj->EnergyMid.EnergyMid_5 = utemp5 % obj->Energy_K;
    #endif
    #if BL0906_CF6_EN
    utemp6 = utemp6*1000 + obj->EnergyMid.EnergyMid_6;
    obj->EnergyMid.EnergyMid_6 = utemp6 % obj->Energy_K;
    #endif
    #if BL0906_CF_EN
    utempSum = utempSum*1000 + obj->EnergyMid.EnergyMid_Sum;
    obj->EnergyMid.EnergyMid_Sum = utempSum % obj->Energy_K;
    #endif

    xSemaphoreTake(obj->Energy_lock, portMAX_DELAY);
    #if BL0906_CF1_EN
    obj->Energy.Energy_1 = obj->Energy.Energy_1 + utemp1/obj->Energy_K;
    #endif
    #if BL0906_CF2_EN
    obj->Energy.Energy_2 = obj->Energy.Energy_2 + utemp2/obj->Energy_K;
    #endif
    #if BL0906_CF3_EN
    obj->Energy.Energy_3 = obj->Energy.Energy_3 + utemp3/obj->Energy_K;
    #endif
    #if BL0906_CF4_EN
    obj->Energy.Energy_4 = obj->Energy.Energy_4 + utemp4/obj->Energy_K;
    #endif
    #if BL0906_CF5_EN
    obj->Energy.Energy_5 = obj->Energy.Energy_5 + utemp5/obj->Energy_K;
    #endif
    #if BL0906_CF6_EN
    obj->Energy.Energy_6 = obj->Energy.Energy_6 + utemp6/obj->Energy_K;
    #endif
    #if BL0906_CF_EN
    obj->Energy.Energy_Sum = obj->Energy.Energy_Sum + utempSum/obj->Energy_K;
    #endif
    xSemaphoreGive(obj->Energy_lock);
#endif

#else   /* CF不清零 */
#if BL0906_ENERGY_USE_FLOAT /* 能量使用浮点运算 */
    xSemaphoreTake(obj->Energy_lock, portMAX_DELAY);
    #if BL0906_CF1_EN
    obj->Energy.Energy_1 = obj->EnergyMid.EnergyMid_1 + (float)utemp1/obj->Energy_K;
    #endif
    #if BL0906_CF2_EN
    obj->Energy.Energy_2 = obj->EnergyMid.EnergyMid_2 + (float)utemp2/obj->Energy_K;
    #endif
    #if BL0906_CF3_EN
    obj->Energy.Energy_3 = obj->EnergyMid.EnergyMid_3 + (float)utemp3/obj->Energy_K;
    #endif
    #if BL0906_CF4_EN
    obj->Energy.Energy_4 = obj->EnergyMid.EnergyMid_4 + (float)utemp4/obj->Energy_K;
    #endif
    #if BL0906_CF5_EN
    obj->Energy.Energy_5 = obj->EnergyMid.EnergyMid_5 + (float)utemp5/obj->Energy_K;
    #endif
    #if BL0906_CF6_EN
    obj->Energy.Energy_6 = obj->EnergyMid.EnergyMid_6 + (float)utemp6/obj->Energy_K;
    #endif
    #if BL0906_CF_EN
    obj->Energy.Energy_Sum = obj->EnergyMid.EnergyMid_Sum + (float)utempSum/obj->Energy_K;
    #endif
    xSemaphoreGive(obj->Energy_lock);
#else    /* 能量使用整形运算 */
    xSemaphoreTake(obj->Energy_lock, portMAX_DELAY);
    #if BL0906_CF1_EN
    obj->Energy.Energy_1 = obj->EnergyMid.EnergyMid_1 + utemp1*1000/obj->Energy_K;
    #endif
    #if BL0906_CF2_EN
    obj->Energy.Energy_2 = obj->EnergyMid.EnergyMid_2 + utemp2*1000/obj->Energy_K;
    #endif
    #if BL0906_CF3_EN
    obj->Energy.Energy_3 = obj->EnergyMid.EnergyMid_3 + utemp3*1000/obj->Energy_K;
    #endif
    #if BL0906_CF4_EN
    obj->Energy.Energy_4 = obj->EnergyMid.EnergyMid_4 + utemp4*1000/obj->Energy_K;
    #endif
    #if BL0906_CF5_EN
    obj->Energy.Energy_5 = obj->EnergyMid.EnergyMid_5 + utemp5*1000/obj->Energy_K;
    #endif
    #if BL0906_CF6_EN
    obj->Energy.Energy_6 = obj->EnergyMid.EnergyMid_6 + utemp6*1000/obj->Energy_K;
    #endif
    #if BL0906_CF_EN
    obj->Energy.Energy_Sum = obj->EnergyMid.EnergyMid_Sum + utempSum*1000/obj->Energy_K;
    #endif
    xSemaphoreGive(obj->Energy_lock);
#endif

    if ((utemp1 > 0x7FFFFF) || (utemp2 > 0x7FFFFF) || (utemp3 > 0x7FFFFF) || (utemp4 > 0x7FFFFF) ||
        (utemp5 > 0x7FFFFF) || (utemp6 > 0x7FFFFF) || (utempSum > 0x7FFFFF)) /* 超限清零 */
    {
        #if BL0906_CF1_EN
        obj->EnergyMid.EnergyMid_1 = obj->Energy.Energy_1;
        #endif
        #if BL0906_CF2_EN
        obj->EnergyMid.EnergyMid_2 = obj->Energy.Energy_2;
        #endif
        #if BL0906_CF3_EN
        obj->EnergyMid.EnergyMid_3 = obj->Energy.Energy_3;
        #endif
        #if BL0906_CF4_EN
        obj->EnergyMid.EnergyMid_4 = obj->Energy.Energy_4;
        #endif
        #if BL0906_CF5_EN
        obj->EnergyMid.EnergyMid_5 = obj->Energy.Energy_5;
        #endif
        #if BL0906_CF6_EN
        obj->EnergyMid.EnergyMid_6 = obj->Energy.Energy_6;
        #endif
        #if BL0906_CF_EN
        obj->EnergyMid.EnergyMid_Sum = obj->Energy.Energy_Sum;
        #endif

        Bl0906_WriteReg( obj, Addr_USR_WRPROT_, 0x5555, false );
        Bl0906_WriteReg( obj, Addr_SOFT_RESET_, 0x5A5A5A, false );
        Bl0906_Config( obj );
    }

#endif
}

#if BL0906_SETMN_RETRY_EN
static uint32_t bl0906_mn_mask = 0xFFF000;
static volatile uint8_t bl0906_mn_state = 1;    /* 0：错误，1：正确/进行中 */
/**
 * @brief 继电器控制失败
 */
void Bl0906_SetMn_retry_thread_entry(void *para)
{
    Bl0906_t *obj = (Bl0906_t *)para;
    while (1)
    {
        if (bl0906_mn_state == 0)
        {
            Bl0906_WriteReg( obj, Addr_USR_WRPROT_, 0x5555, false );
            if (BSP_SUCCESS == Bl0906_WriteReg(obj, Addr_FLAG_CTRL, bl0906_mn_mask, true))
            {
                bl0906_mn_state = 1;
            }
            else
            {
                vTaskDelay(5000);
            }
        }
        vTaskDelay(10);
    }
}

/**
 * @brief BL0906报警输出手动控制
 * @param[in]  obj      Bl0906对象
 * @param[in]  mask     BL_Mx_EN的组合（BL_M1_EN|BL_M2_EN）
 * @param[in]  en       电平
 * @return int8_t 
 * - @b Sucess :  \n
 * - @b Fail
 * - @ref BSP_ERROR_INVALID_PARAM - 非法入参
 * - @ref BSP_ERROR_NO_INIT - 未初始化
 * - @ref BSP_ERROR @ref BSP_ERROR_CHECK
 * @par 示例:
 * @code
 *    Bl0906_SetMn( obj, BL_M1_EN | BL_M2_EN | BL_M5_EN, ture );
 * @endcode
 */
int8_t Bl0906_SetMn( Bl0906_t *obj, uint16_t mask, bool en )
{
    if ((obj == NULL) || (mask == 0))
        return BSP_ERROR_INVALID_PARAM;

    if ( !obj->IsInitialized )
        return BSP_ERROR_NO_INIT;

    bl0906_mn_mask = (en) ? (bl0906_mn_mask|mask) : (bl0906_mn_mask&(~mask));
    Bl0906_WriteReg( obj, Addr_USR_WRPROT_, 0x5555, false );
    int8_t ret = Bl0906_WriteReg( obj, Addr_FLAG_CTRL, bl0906_mn_mask, true );
    bl0906_mn_state = (ret == BSP_SUCCESS) ? 1 : 0;

    return ret;
}


#else
int8_t Bl0906_SetMn( Bl0906_t *obj, uint16_t mask, bool en )
{
    if ((obj == NULL) || (mask == 0))
        return BSP_ERROR_INVALID_PARAM;

    if ( !obj->IsInitialized )
        return BSP_ERROR_NO_INIT;

    uint32_t utemp;
    int8_t ret = Bl0906_ReadRegUint( obj, Addr_FLAG_CTRL, &utemp );
    if (BSP_SUCCESS != ret)
        return ret;

    utemp = utemp | 0xFFF000;
    Bl0906_WriteReg( obj, Addr_USR_WRPROT_, 0x5555, false );
    if(en)
        ret =  Bl0906_WriteReg( obj, Addr_FLAG_CTRL, utemp|mask, true );
    else
    {
        utemp &= ~mask;
        ret =  Bl0906_WriteReg( obj, Addr_FLAG_CTRL, utemp, true );
    }
    Bl0906_WriteReg( obj, Addr_USR_WRPROT_, 0x000000, false );

    return ret;
}
#endif

static void Bl0906_Config(Bl0906_t *obj)
{
    /* 开用户写保护 */
    if( BSP_SUCCESS != Bl0906_WriteReg( obj, Addr_USR_WRPROT_, 0x5555, true ) )
    {
        log_e( "Bl0906_WriteReg Addr_USR_WRPROT fail\r\n" );
        return;
    }

    /* 防潜动阈值设置，有功功率设置1W以下切除到零 */
    if( BSP_SUCCESS != Bl0906_WriteReg( obj, Addr_VAR_WATT_CREEP, (uint32_t)(obj->Power_K*2), true ) )
        return;
    
    /* 快速有效值设置为过高通 */
    if( BSP_SUCCESS != Bl0906_WriteReg( obj, Addr_MODE1, 0x400000, true ) )
        return;
    
    /* 电能脉冲读后清零设置，Reg3B~2F设置为读后清零 */
#if BL0906_CF_CLR_SEL
    if( BSP_SUCCESS != Bl0906_WriteReg( obj, Addr_RST_ENG, 0x1FF, true ) )
#else
    if( BSP_SUCCESS != Bl0906_WriteReg( obj, Addr_RST_ENG, 0x000, true ) )
#endif
        return;

    Bl0906_WriteReg( obj, Addr_CFDIV, 0x20, true );    /* CFDIV = 32 */
}

/**
 * @brief Bl0906初始化
 * @param[in]  obj      Bl0906对象
 * @param[in]  uartId   串口外设编号
 * @param[in]  tx       串口TX引脚
 * @param[in]  rx       串口RX引脚
 * @return int8_t 
 * - @b Sucess : BSP_SUCCESS \n
 * - @b Fail
 * - @ref BSP_ERROR_INVALID_PARAM - 非法入参
 * - @ref BSP_ERROR_ALREADY_INIT - 已初始化
 * - @ref BSP_ERROR - 初始化出错
 * - @ref BSP_ERROR_NO_MEM - 内存出错
 */
int8_t Bl0906_Init( Bl0906_t *obj, UartId_t uartId, PinNames tx, PinNames rx )
{
    if (obj == NULL)
        return BSP_ERROR_INVALID_PARAM;

    if( obj->IsInitialized )
    {
        log_e( "Bl0906_Init error: has already Initialized\r\n" );
        return BSP_ERROR_ALREADY_INIT;
    }

    obj->UartId = uartId;
    if(BSP_SUCCESS != UartInit( uartId, tx, rx, 64 ))
        return BSP_ERROR;
    UartConfig( uartId, RX_TX, 9600, UART_8_BIT, UART_1_STOP_BIT, NO_PARITY, NO_FLOW_CTRL );

    /* 电参数计算系数设置 */
#if BL0906_ELECT_USE_FLOAT
    obj->Current_K = 59829.157;     /* (206000*5.1)/(1.0975*16) = 59829.157 */
    obj->L_Current_K = 59829.157;
    obj->Voltage_K = 12016.74;      /* 13162*(200/49.9*4)/1.0975 = 12016.74 */
    obj->Power_K = 171.45;          /* 646.6*5.1*(200/49.9*4)/(1.0975*1.0975)/16 = 171.453 */
#else
    obj->Current_K = 59829;
    obj->L_Current_K = 59829;
    obj->Voltage_K = 12016;
    obj->Power_K = 171;
#endif

#if BL0906_ENERGY_USE_FLOAT
    obj->Energy_K = 8981.915;       /* 32*3600000*Power_K/(4194304*0.032768*16) = 8981.915 */
#else
    obj->Energy_K = 8982;
#endif

    /* 电量统计清零 */
    memset( &obj->Energy, 0, sizeof(Bl0906_Energy_t) );
#if !(BL0906_ENERGY_USE_FLOAT && BL0906_CF_CLR_SEL)
    memset( &obj->EnergyMid, 0, sizeof(Bl0906_EnergyMid_t) );
#endif

    /* RS485通信锁 */
    obj->WR_lock = xSemaphoreCreateBinary();    /* 初始时信号值为0 */
    if(obj->WR_lock == NULL)
    {
        log_e("bl0906 WR_lock create error\r\n");
        return BSP_ERROR_NO_MEM;
    }
    xSemaphoreGive(obj->WR_lock);


    /* 开用户写保护 */
    if( BSP_SUCCESS != Bl0906_WriteReg( obj, Addr_USR_WRPROT_, 0x5555, true ) )
    {
        log_e( "Bl0906_WriteReg Addr_USR_WRPROT fail\r\n" );
        return BSP_ERROR;
    }
    vTaskDelay(1);

    Bl0906_WriteReg( obj, Addr_SOFT_RESET_, 0x5A5A5A, false );
    Bl0906_WriteReg( obj, Addr_SOFT_RESET_, 0x55AA55, false );
    Bl0906_WriteReg( obj, Addr_USR_WRPROT_, 0x5555, false );

    /* 脉冲输出选择 */
    if( BSP_SUCCESS !=Bl0906_WriteReg( obj, Addr_MODE3, 0x000000, true ) )   /* 1通道，无功选全波(0x010A00) */
    {
        log_e( "Bl0906_WriteReg Addr_MODE3 fail\r\n" );
        return BSP_ERROR;
    }

    /* 电流通道16倍增益，电压通道1倍增益 */
    Bl0906_WriteReg( obj, Addr_GAIN1, 0x000000, false );    /* 0x222200 8倍 */
    Bl0906_WriteReg( obj, Addr_GAIN2, 0x000000, false );    /* 0x002200 8倍*/

    /* 防潜动阈值设置，电流有效值设置2mA以下切除到零，有功功率设置4W以下切除到零;阈值大小根据实际情况设置 */
    // Bl0906_WriteReg( obj, Addr_RMS_CREEP, obj->Current_K/1000, true );           /* Creep=RMS/2 */
    Bl0906_WriteReg( obj, Addr_VAR_WATT_CREEP, (uint32_t)(obj->Power_K*2), true );  /* Creep=Watt/2 */

    /* 快速有效值设置为过高通 */
    Bl0906_WriteReg( obj, Addr_MODE1, 0x400000, false );

    /* 电能脉冲读后清零设置，Reg3B~2F设置为读后清零 */
#if BL0906_CF_CLR_SEL
    Bl0906_WriteReg( obj, Addr_RST_ENG, 0x1FF, false );
#else
    Bl0906_WriteReg( obj, Addr_RST_ENG, 0x000, false );
#endif
    Bl0906_WriteReg( obj, Addr_CFDIV, 0x20, false );    /* CFDIV = 32 */
    // Bl0906_WriteReg( obj, Addr_ADC_PD, 0x4C2, false );

    /* 电参数运算系统复位，Reg3B~2F清零 */
    Bl0906_WriteReg( obj, Addr_SOFT_RESET_, 0x5A5A5A, false );
    vTaskDelay(2);
    
    Bl0906_WriteReg( obj, Addr_FLAG_CTRL, 0xFFF000, false ); /* M1-M6 开机全开 */

    /* 关闭写保护 */
    Bl0906_WriteReg( obj, Addr_USR_WRPROT_, 0x000000, false );

    /* 电量统计读写锁 */
    obj->Energy_lock = xSemaphoreCreateBinary();
    if(obj->Energy_lock == NULL)
    {
        log_e("bl0906 Energy_lock create error\r\n");
        return BSP_ERROR_NO_MEM;
    }
    xSemaphoreGive(obj->Energy_lock);

    /* 电量统计定时器 */
    obj->bl_timer = xTimerCreate("bl0906", BL0906_ENERGY_PERIOD * portTICK_RATE_MS, pdTRUE, obj, blTimer_timeout_ind);
    if(obj->bl_timer == NULL)
    {
        log_e("bl0906 bl_timer create error\r\n");
        return BSP_ERROR_NO_MEM;
    }
    xTimerStart( obj->bl_timer, 0 );

#if BL0906_SETMN_RETRY_EN
    if( xTaskCreate( Bl0906_SetMn_retry_thread_entry, "bl_mn", BL0906_SETMN_RETRY_STK_SIZE, (void *)obj, BL0906_SETMN_RETRY_TASK_PRIO, NULL) != pdPASS)
    {
        log_e("Bl0906_SetMn_retry_thread_entry create error\r\n");
        return BSP_ERROR_NO_MEM;
    }
#endif

    obj->IsInitialized = true;

    return BSP_SUCCESS;
}

/**
 * @brief Bl0906去初始化
 * @param  obj         Bl0906对象
 */
void Bl0906_DeInit( Bl0906_t *obj )
{
    if (obj == NULL)
        return;

    obj->IsInitialized = false;
    UartDeInit( obj->UartId );

    if (obj->WR_lock)
        vSemaphoreDelete( obj->WR_lock );
    if (obj->Energy_lock)
        vSemaphoreDelete( obj->Energy_lock );
    if (obj->bl_timer)
        xTimerDelete( obj->bl_timer, 0 );
}

/**
 * @brief Bl0906软件复位
 * @param  obj         Bl0906对象
 * @param  Rst_Type    复位类型，0：系统复位，1：寄存器复位
 */
void Bl0906_SoftRst( Bl0906_t *obj, uint8_t	Rst_Type )
{
    Bl0906_WriteReg( obj, Addr_USR_WRPROT_, 0x5555, false );
    vTaskDelay(1);
    Bl0906_WriteReg( obj, Addr_SOFT_RESET_, 0x5A5A5A, false );
    if( Rst_Type == 0 )
        Bl0906_WriteReg( obj, Addr_SOFT_RESET_, 0x5A5A5A, false );
    else
        Bl0906_WriteReg( obj, Addr_SOFT_RESET_, 0x55AA55, false );
    vTaskDelay(1);
}

/**
 * @brief Bl0906设置电量值
 * @param[in]  obj      Bl0906对象
 * @param[in]  Energy   各通道电量值及总电量值设置
 * @return int8_t 
 * - @b Sucess : BSP_SUCCESS \n
 * - @b Fail
 * - @ref BSP_ERROR_INVALID_PARAM - 非法入参
 * - @ref BSP_ERROR_NO_INIT - 未初始化
 */
int8_t Bl0906_SetEnergy( Bl0906_t *obj, Bl0906_Energy_t *Energy )
{
    if ((obj == NULL) || (Energy == NULL))
        return BSP_ERROR_INVALID_PARAM;
    
    if ( !obj->IsInitialized )
        return BSP_ERROR_NO_INIT;

    xSemaphoreTake(obj->Energy_lock, portMAX_DELAY);
    memcpy( &obj->Energy, Energy, sizeof(Bl0906_Energy_t) );
#if !(BL0906_ENERGY_USE_FLOAT && BL0906_CF_CLR_SEL)
    memset( &obj->EnergyMid, 0, sizeof(Bl0906_EnergyMid_t) );
#endif
    xSemaphoreGive(obj->Energy_lock);

#if !BL0906_CF_CLR_SEL
    Bl0906_WriteReg( obj, Addr_USR_WRPROT_, 0x5555, false );
    Bl0906_WriteReg( obj, Addr_SOFT_RESET_, 0x5A5A5A, false );
    Bl0906_Config( obj );
#endif

    return BSP_SUCCESS;
}

/**
 * @brief Bl0906获取电量值
 * @param[in]  obj      Bl0906对象
 * @param[in]  Energy   统计的电量信息结构体
 * @return int8_t 
 * - @b Sucess : BSP_SUCCESS \n
 * - @b Fail
 * - @ref BSP_ERROR_INVALID_PARAM - 非法入参
 * - @ref BSP_ERROR_NO_INIT - 未初始化
 */
int8_t Bl0906_GetEnergy( Bl0906_t *obj, Bl0906_Energy_t *Energy )
{
    if ((obj == NULL) || (Energy == NULL))
        return BSP_ERROR_INVALID_PARAM;

    if( !obj->IsInitialized )
        return BSP_ERROR_NO_INIT;

    xSemaphoreTake(obj->Energy_lock, portMAX_DELAY);
    memcpy( Energy, &obj->Energy, sizeof(Bl0906_Energy_t) );
    xSemaphoreGive(obj->Energy_lock);

    return BSP_SUCCESS;
}

/**
 * @brief 获取电量瞬时参数
 * @param[in]  obj      Bl0906对象
 * @param[in]  Elect    电参数信息
 * @param[in]  mask     电参数选项掩码
 * @return int8_t 
 * - @b Sucess :  \n
 * - @b Fail
 * - @ref BSP_ERROR_INVALID_PARAM - 非法入参
 * - @ref BSP_ERROR_NO_INIT - 未初始化
 * - 其他寄存器读取错误
 * @par 示例:
 * @code
 *    Bl0906_GetElect( obj, Elect, BL0906_ELECT_P_ALL );
 *    Bl0906_GetElect( obj, Elect, BL0906_ELECT_V | BL0906_ELECT_I_1 );
 * @endcode
 */
int8_t Bl0906_GetElect( Bl0906_t *obj, Bl0906_Elect_t *Elect, uint32_t mask )
{
    uint32_t utemp;
    int32_t itemp;
    int8_t ret;

    if ((obj == NULL) || (Elect == NULL) || (mask == 0))
        return BSP_ERROR_INVALID_PARAM;

    if (!obj->IsInitialized)
    {
        log_e( "Bl0906 no Initialized\r\n" );
        return BSP_ERROR_NO_INIT;
    }

#if BL0906_V_RMS_EN
    if (mask & BL0906_ELECT_V)      /* 读电压有效值 unit: 0.1伏 */
    {
        ret = Bl0906_ReadRegUint( obj, Addr_V_RMS_, &utemp );
        if (ret != BSP_SUCCESS)
            goto error_handle;

        log_v("Addr_V_RMS_ = %d\r\n", utemp);
#if BL0906_ELECT_USE_FLOAT
        Elect->RMS_V = (float)utemp/obj->Voltage_K;
        log_v("RMS_V = %.3f\r\n", Elect->RMS_V);
#else
        Elect->RMS_V = utemp*10/obj->Voltage_K;
        log_v("RMS_V = %d\r\n", Elect->RMS_V);
#endif
    }
#endif

#if BL0906_PERIOD_EN
    if (mask & BL0906_ELECT_PERIOD) /* 读工频 unit: 0.01Hz */
    {
        ret = Bl0906_ReadRegUint( obj, Addr_PERIOD, &utemp );
        if (ret != BSP_SUCCESS)
            goto error_handle;

        log_v("Addr_PERIOD = %d\r\n", utemp);
#if BL0906_ELECT_USE_FLOAT
        Elect->Period = (float)10000000/((float)utemp);
        log_v("Period = %.3f\r\n", Elect->Period);
#else
        Elect->Period = 10000000*100/utemp;
        log_v("Period = %d\r\n", Elect->Period);
#endif
    }
#endif

#if BL0906_1_RMS_EN
    if (mask & BL0906_ELECT_I_1)    /* 读电流有效值 unit: 0.001安 */
    {
        ret = Bl0906_ReadRegUint( obj, Addr_1_RMS, &utemp );
        if (ret != BSP_SUCCESS)
            goto error_handle;

        log_v("Addr_1_RMS = %d\r\n", utemp);
#if BL0906_ELECT_USE_FLOAT
        Elect->RMS_1 = (float)utemp/obj->Current_K;
        log_v("RMS_1 = %.3f\r\n", Elect->RMS_1);
#else
        Elect->RMS_1 = utemp*1000/obj->Current_K;
        log_v("RMS_1 = %d\r\n", Elect->RMS_1);
#endif
#if (BL0906_RMS_CREEP_VALUE > 0)
        #if BL0906_ELECT_USE_FLOAT
        Elect->RMS_1 = (Elect->RMS_1 < (float)BL0906_RMS_CREEP_VALUE/1000) ? 0 : Elect->RMS_1;
        #else
        Elect->RMS_1 = (Elect->RMS_1 < BL0906_RMS_CREEP_VALUE) ? 0 : Elect->RMS_1;
        #endif
#endif
    }
#endif
#if BL0906_2_RMS_EN
    if (mask & BL0906_ELECT_I_2)
    {
        ret = Bl0906_ReadRegUint( obj, Addr_2_RMS, &utemp );
        if (ret != BSP_SUCCESS)
            goto error_handle;

        log_v("Addr_2_RMS = %d\r\n", utemp);
#if BL0906_ELECT_USE_FLOAT
        Elect->RMS_2 = (float)utemp/obj->Current_K;
        log_v("RMS_2 = %.3f\r\n", Elect->RMS_2);
#else
        Elect->RMS_2 = utemp*1000/obj->Current_K;
        log_v("RMS_2 = %d\r\n", Elect->RMS_2);
#endif
#if (BL0906_RMS_CREEP_VALUE > 0)
        #if BL0906_ELECT_USE_FLOAT
        Elect->RMS_2 = (Elect->RMS_2 < (float)BL0906_RMS_CREEP_VALUE/1000) ? 0 : Elect->RMS_2;
        #else
        Elect->RMS_2 = (Elect->RMS_2 < BL0906_RMS_CREEP_VALUE) ? 0 : Elect->RMS_2;
        #endif
#endif
    }
#endif
#if BL0906_3_RMS_EN
    if (mask & BL0906_ELECT_I_3)
    {
        ret = Bl0906_ReadRegUint( obj, Addr_3_RMS, &utemp );
        if (ret != BSP_SUCCESS)
            goto error_handle;

        log_v("Addr_3_RMS = %d\r\n", utemp);
#if BL0906_ELECT_USE_FLOAT
        Elect->RMS_3 = (float)utemp/obj->Current_K;
        log_v("RMS_3 = %.3f\r\n", Elect->RMS_3);
#else
        Elect->RMS_3 = utemp*1000/obj->Current_K;
        log_v("RMS_3 = %d\r\n", Elect->RMS_3);
#endif
#if (BL0906_RMS_CREEP_VALUE > 0)
        #if BL0906_ELECT_USE_FLOAT
        Elect->RMS_3 = (Elect->RMS_3 < (float)BL0906_RMS_CREEP_VALUE/1000) ? 0 : Elect->RMS_3;
        #else
        Elect->RMS_3 = (Elect->RMS_3 < BL0906_RMS_CREEP_VALUE) ? 0 : Elect->RMS_3;
        #endif
#endif
    }
#endif
#if BL0906_4_RMS_EN
    if (mask & BL0906_ELECT_I_4)
    {
        ret = Bl0906_ReadRegUint( obj, Addr_4_RMS, &utemp );
        if (ret != BSP_SUCCESS)
            goto error_handle;

        log_v("Addr_4_RMS = %d\r\n", utemp);
#if BL0906_ELECT_USE_FLOAT
        Elect->RMS_4 = (float)utemp/obj->Current_K;
        log_v("RMS_4 = %.3f\r\n", Elect->RMS_4);
#else
        Elect->RMS_4 = utemp*1000/obj->Current_K;
        log_v("RMS_4 = %d\r\n", Elect->RMS_4);
#endif
#if (BL0906_RMS_CREEP_VALUE > 0)
        #if BL0906_ELECT_USE_FLOAT
        Elect->RMS_4 = (Elect->RMS_4 < (float)BL0906_RMS_CREEP_VALUE/1000) ? 0 : Elect->RMS_4;
        #else
        Elect->RMS_4 = (Elect->RMS_4 < BL0906_RMS_CREEP_VALUE) ? 0 : Elect->RMS_4;
        #endif
#endif
    }
#endif
#if BL0906_5_RMS_EN
    if (mask & BL0906_ELECT_I_5)
    {
        ret = Bl0906_ReadRegUint( obj, Addr_5_RMS, &utemp );
        if (ret != BSP_SUCCESS)
            goto error_handle;

        log_v("Addr_5_RMS = %d\r\n", utemp);
#if BL0906_ELECT_USE_FLOAT
        Elect->RMS_5 = (float)utemp/obj->Current_K;
        log_v("RMS_5 = %.3f\r\n", Elect->RMS_5);
#else
        Elect->RMS_5 = utemp*1000/obj->Current_K;
        log_v("RMS_5 = %d\r\n", Elect->RMS_5);
#endif
#if (BL0906_RMS_CREEP_VALUE > 0)
        #if BL0906_ELECT_USE_FLOAT
        Elect->RMS_5 = (Elect->RMS_5 < (float)BL0906_RMS_CREEP_VALUE/1000) ? 0 : Elect->RMS_5;
        #else
        Elect->RMS_5 = (Elect->RMS_5 < BL0906_RMS_CREEP_VALUE) ? 0 : Elect->RMS_5;
        #endif
#endif
    }
#endif
#if BL0906_6_RMS_EN
    if (mask & BL0906_ELECT_I_6)
    {
        ret = Bl0906_ReadRegUint( obj, Addr_6_RMS, &utemp );
        if (ret != BSP_SUCCESS)
            goto error_handle;

        log_v("Addr_6_RMS = %d\r\n", utemp);
#if BL0906_ELECT_USE_FLOAT
        Elect->RMS_6 = (float)utemp/obj->Current_K;
        log_v("RMS_6 = %.3f\r\n", Elect->RMS_6);
#else
        Elect->RMS_6 = utemp*1000/obj->Current_K;
        log_v("RMS_6 = %d\r\n", Elect->RMS_6);
#endif
#if (BL0906_RMS_CREEP_VALUE > 0)
        #if BL0906_ELECT_USE_FLOAT
        Elect->RMS_6 = (Elect->RMS_6 < (float)BL0906_RMS_CREEP_VALUE/1000) ? 0 : Elect->RMS_6;
        #else
        Elect->RMS_6 = (Elect->RMS_6 < BL0906_RMS_CREEP_VALUE) ? 0 : Elect->RMS_6;
        #endif
#endif
    }
#endif

#if BL0906_WATT1_EN
    if (mask & BL0906_ELECT_P_1)    /* 读有功功率 unit: 0.1瓦 */
    {
        ret = Bl0906_ReadRegInt( obj, Addr_WATT1, &itemp );
        if (ret != BSP_SUCCESS)
            goto error_handle;

        log_v("Addr_WATT1 = %d\r\n", itemp);
#if BL0906_ELECT_USE_FLOAT
        Elect->WATT_1 = (float)abs(itemp)/obj->Power_K;
        log_v("WATT_1 = %.3f\r\n", Elect->WATT_1);
#else
        Elect->WATT_1 = abs(itemp)*100/obj->Power_K;
        log_v("WATT_1 = %d\r\n", Elect->WATT_1);
#endif
    }
#endif
#if BL0906_WATT2_EN
    if (mask & BL0906_ELECT_P_2)
    {
        ret = Bl0906_ReadRegInt( obj, Addr_WATT2, &itemp );
        if (ret != BSP_SUCCESS)
            goto error_handle;

        log_v("Addr_WATT2 = %d\r\n", itemp);
#if BL0906_ELECT_USE_FLOAT
        Elect->WATT_2 = (float)abs(itemp)/obj->Power_K;
        log_v("WATT_2 = %.3f\r\n", Elect->WATT_2);
#else
        Elect->WATT_2 = abs(itemp)*100/obj->Power_K;
        log_v("WATT_2 = %d\r\n", Elect->WATT_2);
#endif
    }
#endif
#if BL0906_WATT3_EN
    if (mask & BL0906_ELECT_P_3)
    {
        ret = Bl0906_ReadRegInt( obj, Addr_WATT3, &itemp );
        if (ret != BSP_SUCCESS)
            goto error_handle;

        log_v("Addr_WATT3 = %d\r\n", itemp);
#if BL0906_ELECT_USE_FLOAT
        Elect->WATT_3 = (float)abs(itemp)/obj->Power_K;
        log_v("WATT_3 = %.3f\r\n", Elect->WATT_3);
#else
        Elect->WATT_3 = abs(itemp)*100/obj->Power_K;
        log_v("WATT_3 = %d\r\n", Elect->WATT_3);
#endif
    }
#endif
#if BL0906_WATT4_EN
    if (mask & BL0906_ELECT_P_4)
    {
        ret = Bl0906_ReadRegInt( obj, Addr_WATT4, &itemp );
        if (ret != BSP_SUCCESS)
            goto error_handle;

        log_v("Addr_WATT4 = %d\r\n", itemp);
#if BL0906_ELECT_USE_FLOAT
        Elect->WATT_4 = (float)abs(itemp)/obj->Power_K;
        log_v("WATT_4 = %.3f\r\n", Elect->WATT_4);
#else
        Elect->WATT_4 = abs(itemp)*100/obj->Power_K;
        log_v("WATT_4 = %d\r\n", Elect->WATT_4);
#endif
    }
#endif
#if BL0906_WATT5_EN
    if (mask & BL0906_ELECT_P_5)
    {
        ret = Bl0906_ReadRegInt( obj, Addr_WATT5, &itemp );
        if (ret != BSP_SUCCESS)
            goto error_handle;

        log_v("Addr_WATT5 = %d\r\n", itemp);
#if BL0906_ELECT_USE_FLOAT
        Elect->WATT_5 = (float)abs(itemp)/obj->Power_K;
        log_v("WATT_5 = %.3f\r\n", Elect->WATT_5);
#else
        Elect->WATT_5 = abs(itemp)*100/obj->Power_K;
        log_v("WATT_5 = %d\r\n", Elect->WATT_5);
#endif
    }
#endif
#if BL0906_WATT6_EN
    if (mask & BL0906_ELECT_P_6)
    {
        ret = Bl0906_ReadRegInt( obj, Addr_WATT6, &itemp );
        if (ret != BSP_SUCCESS)
            goto error_handle;

        log_v("Addr_WATT6 = %d\r\n", itemp);
#if BL0906_ELECT_USE_FLOAT
        Elect->WATT_6 = (float)abs(itemp)/obj->Power_K;
        log_v("WATT_6 = %.3f\r\n", Elect->WATT_6);
#else
        Elect->WATT_6 = abs(itemp)*100/obj->Power_K;
        log_v("WATT_6 = %d\r\n", Elect->WATT_6);
#endif
    }
#endif

#if BL0906_1_FAST_RMS_EN
    if (mask & BL0906_ELECT_L_1)    /* 读快速有效值（漏电流） unit: 0.001安 */
    {
        ret = Bl0906_ReadRegUint( obj, Addr_1_FAST_RMS, &utemp );
        if (ret != BSP_SUCCESS)
            goto error_handle;

        log_v("Addr_1_FAST_RMS = %d\r\n", utemp);
#if BL0906_ELECT_USE_FLOAT
        Elect->FAST_RMS_1 = (float)utemp/obj->L_Current_K;
        log_v("FAST_RMS_1 = %.3f\r\n", Elect->FAST_RMS_1);
#else
        Elect->FAST_RMS_1 = utemp*1000/obj->L_Current_K;
        log_v("FAST_RMS_1 = %d\r\n", Elect->FAST_RMS_1);
#endif
#if (BL0906_FAST_RMS_CREEP_VALUE > 0)
        #if BL0906_ELECT_USE_FLOAT
        Elect->FAST_RMS_1 = (Elect->FAST_RMS_1 < (float)BL0906_FAST_RMS_CREEP_VALUE/1000) ? 0 : Elect->FAST_RMS_1;
        #else
        Elect->FAST_RMS_1 = (Elect->FAST_RMS_1 < BL0906_FAST_RMS_CREEP_VALUE) ? 0 : Elect->FAST_RMS_1;
        #endif
#endif
    }
#endif
#if BL0906_2_FAST_RMS_EN
    if (mask & BL0906_ELECT_L_2)
    {
        ret = Bl0906_ReadRegUint( obj, Addr_2_FAST_RMS, &utemp );
        if (ret != BSP_SUCCESS)
            goto error_handle;

        log_v("Addr_2_FAST_RMS = %d\r\n", utemp);
#if BL0906_ELECT_USE_FLOAT
        Elect->FAST_RMS_2 = (float)utemp/obj->L_Current_K;
        log_v("FAST_RMS_2 = %.3f\r\n", Elect->FAST_RMS_2);
#else
        Elect->FAST_RMS_2 = utemp*1000/obj->L_Current_K;
        log_v("FAST_RMS_2 = %d\r\n", Elect->FAST_RMS_2);
#endif
#if (BL0906_FAST_RMS_CREEP_VALUE > 0)
        #if BL0906_ELECT_USE_FLOAT
        Elect->FAST_RMS_2 = (Elect->FAST_RMS_2 < (float)BL0906_FAST_RMS_CREEP_VALUE/1000) ? 0 : Elect->FAST_RMS_2;
        #else
        Elect->FAST_RMS_2 = (Elect->FAST_RMS_2 < BL0906_FAST_RMS_CREEP_VALUE) ? 0 : Elect->FAST_RMS_2;
        #endif
#endif
    }
#endif
#if BL0906_3_FAST_RMS_EN
    if (mask & BL0906_ELECT_L_3)
    {
        ret = Bl0906_ReadRegUint( obj, Addr_3_FAST_RMS, &utemp );
        if (ret != BSP_SUCCESS)
            goto error_handle;

        log_v("Addr_3_FAST_RMS = %d\r\n", utemp);
#if BL0906_ELECT_USE_FLOAT
        Elect->FAST_RMS_3 = (float)utemp/obj->L_Current_K;
        log_v("FAST_RMS_3 = %.3f\r\n", Elect->FAST_RMS_3);
#else
        Elect->FAST_RMS_3 = utemp*1000/obj->L_Current_K;
        log_v("FAST_RMS_3 = %d\r\n", Elect->FAST_RMS_3);
#endif
#if (BL0906_FAST_RMS_CREEP_VALUE > 0)
        #if BL0906_ELECT_USE_FLOAT
        Elect->FAST_RMS_3 = (Elect->FAST_RMS_3 < (float)BL0906_FAST_RMS_CREEP_VALUE/1000) ? 0 : Elect->FAST_RMS_3;
        #else
        Elect->FAST_RMS_3 = (Elect->FAST_RMS_3 < BL0906_FAST_RMS_CREEP_VALUE) ? 0 : Elect->FAST_RMS_3;
        #endif
#endif
    }
#endif
#if BL0906_4_FAST_RMS_EN
    if (mask & BL0906_ELECT_L_4)
    {
        ret = Bl0906_ReadRegUint( obj, Addr_4_FAST_RMS, &utemp );
        if (ret != BSP_SUCCESS)
            goto error_handle;

        log_v("Addr_4_FAST_RMS = %d\r\n", utemp);
#if BL0906_ELECT_USE_FLOAT
        Elect->FAST_RMS_4 = (float)utemp/obj->L_Current_K;
        log_v("FAST_RMS_4 = %.3f\r\n", Elect->FAST_RMS_4);
#else
        Elect->FAST_RMS_4 = utemp*1000/obj->L_Current_K;
        log_v("FAST_RMS_4 = %d\r\n", Elect->FAST_RMS_4);
#endif
#if (BL0906_FAST_RMS_CREEP_VALUE > 0)
        #if BL0906_ELECT_USE_FLOAT
        Elect->FAST_RMS_4 = (Elect->FAST_RMS_4 < (float)BL0906_FAST_RMS_CREEP_VALUE/1000) ? 0 : Elect->FAST_RMS_4;
        #else
        Elect->FAST_RMS_4 = (Elect->FAST_RMS_4 < BL0906_FAST_RMS_CREEP_VALUE) ? 0 : Elect->FAST_RMS_4;
        #endif
#endif
    }
#endif
#if BL0906_5_FAST_RMS_EN
    if (mask & BL0906_ELECT_L_5)
    {
        ret = Bl0906_ReadRegUint( obj, Addr_5_FAST_RMS, &utemp );
        if (ret != BSP_SUCCESS)
            goto error_handle;

        log_v("Addr_5_FAST_RMS = %d\r\n", utemp);
#if BL0906_ELECT_USE_FLOAT
        Elect->FAST_RMS_5 = (float)utemp/obj->L_Current_K;
        log_v("FAST_RMS_5 = %.3f\r\n", Elect->FAST_RMS_5);
#else
        Elect->FAST_RMS_5 = utemp*1000/obj->L_Current_K;
        log_v("FAST_RMS_5 = %d\r\n", Elect->FAST_RMS_5);
#endif
#if (BL0906_FAST_RMS_CREEP_VALUE > 0)
        #if BL0906_ELECT_USE_FLOAT
        Elect->FAST_RMS_5 = (Elect->FAST_RMS_5 < (float)BL0906_FAST_RMS_CREEP_VALUE/1000) ? 0 : Elect->FAST_RMS_5;
        #else
        Elect->FAST_RMS_5 = (Elect->FAST_RMS_5 < BL0906_FAST_RMS_CREEP_VALUE) ? 0 : Elect->FAST_RMS_5;
        #endif
#endif
    }
#endif
#if BL0906_6_FAST_RMS_EN
    if (mask & BL0906_ELECT_L_6)
    {
        ret = Bl0906_ReadRegUint( obj, Addr_6_FAST_RMS, &utemp );
        if (ret != BSP_SUCCESS)
            goto error_handle;

        log_v("Addr_6_FAST_RMS = %d\r\n", utemp);
#if BL0906_ELECT_USE_FLOAT
        Elect->FAST_RMS_6 = (float)utemp/obj->L_Current_K;
        log_v("FAST_RMS_6 = %.3f\r\n", Elect->FAST_RMS_6);
#else
        Elect->FAST_RMS_6 = utemp*1000/obj->L_Current_K;
        log_v("FAST_RMS_6 = %d\r\n", Elect->FAST_RMS_6);
#endif
#if (BL0906_FAST_RMS_CREEP_VALUE > 0)
        #if BL0906_ELECT_USE_FLOAT
        Elect->FAST_RMS_6 = (Elect->FAST_RMS_6 < (float)BL0906_FAST_RMS_CREEP_VALUE/1000) ? 0 : Elect->FAST_RMS_6;
        #else
        Elect->FAST_RMS_6 = (Elect->FAST_RMS_6 < BL0906_FAST_RMS_CREEP_VALUE) ? 0 : Elect->FAST_RMS_6;
        #endif
#endif
    }
#endif

    return BSP_SUCCESS;

error_handle:
    log_e( "Bl0906_ReadReg error(%d)\r\n", ret );
    return ret;
}



#endif    /* BL0906_EN */

/*********** (C) COPYRIGHT 2020 FiberHome *****END OF FILE****/
